package com.wish.wishsystem_management.config;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.elasticsearch.action.search.SearchResponse;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;


/**
 * es的工具类型
 *
 * @author 翟伟佳
 */
public class EsUtils {

    private EsUtils() {

    }

    /**
     * 数据保存/更新的操作
     *
     * @param elasticsearchTemplate 操作的模板对象
     * @param object                保存的实体对象
     * @param id                    实体对象对应的id值
     * @throws Exception
     */
    public static void save(ElasticsearchTemplate elasticsearchTemplate, Object object, String id) throws Exception {
        IndexQuery query = new IndexQueryBuilder().withObject(object).withId(id).build();
        elasticsearchTemplate.index(query);
    }

    /**
     * 删除数据操作
     *
     * @param elasticsearchTemplate 操作的模板对象
     * @param clazz                 实体对象的clazz类型
     * @param ids                   要删除的数组id集合
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static void delete(ElasticsearchTemplate elasticsearchTemplate, Class clazz, String ids[]) throws Exception {
        for (String id : ids) {
            elasticsearchTemplate.delete(clazz, id);
        }
    }

    /**
     * 查询数据操作
     *
     * @param elasticsearchTemplate 操作模板对象
     * @param clazz                 操作实体类类型
     * @param pageNum               当前页
     * @param pageSize              每页显示的记录数
     * @param direction             排序的方式
     * @param sortFields            排序的字段
     * @param value                 查询的内容
     * @param fields                查询的字段
     * @param field                 权重的字段
     * @param boost                 权重的值
     * @return
     */
    @SuppressWarnings("unchecked")
    public static PageInfo search(ElasticsearchTemplate elasticsearchTemplate, Class clazz, Integer pageNum,
                                  Integer pageSize, String direction, String sortFields, String value, String fields[], String field,
                                  float boost) {
        // 设置分页
        PageRequest pageable = null;
        // 加入排序的判断
        if ("asc".equals(direction)) {
            pageable = PageRequest.of(pageNum - 1, pageSize, Sort.by(Direction.ASC, sortFields));
        } else {
            pageable = PageRequest.of(pageNum - 1, pageSize, Sort.by(Direction.DESC, sortFields));
        }

        // 构建查询条件
        MultiMatchQueryBuilder queryBuilder = null;
        SearchQuery searchQuery = null;
        AggregatedPage page = null;

        if (value != null && !"".equals(value)) {

            queryBuilder = new MultiMatchQueryBuilder(value, fields);

            if (field != null) {
                // 权重的问题
                queryBuilder.field(field, boost);
            }

            // 创建高亮字段值
            HighlightBuilder.Field highlightFields[] = new HighlightBuilder.Field[fields.length];
            // 设置字段前后缀
            for (int i = 0; i < highlightFields.length; i++) {
                highlightFields[i] = new HighlightBuilder.Field(fields[i]).preTags("<font color='red'>")
                        .postTags("</font>");
            }
            // 创建查询条件对象
            searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).withQuery(queryBuilder)
                    .withHighlightFields(highlightFields).build();

            // 执行查询效果
            page = elasticsearchTemplate.queryForPage(searchQuery, clazz, new SearchResultMapper() {

                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {

                    List<T> list = new ArrayList<>();

                    // 命中数据
                    SearchHits hits = response.getHits();
                    long totalHits = hits.getTotalHits();

                    // 命中的数据
                    SearchHit[] hits2 = hits.getHits();
                    for (SearchHit hit : hits2) {
                        // 获取原数据的json数据
                        String sourceAsString = hit.getSourceAsString();
                        // json转换实体对象
                        T entity = JSON.parseObject(sourceAsString, clazz);
                        // 获取高亮字段值
                        Map<String, HighlightField> highlightFields2 = hit.getHighlightFields();
                        try {
                            for (int i = 0; i < fields.length; i++) {
                                // 获取高亮的字段
                                HighlightField highlightField = highlightFields2.get(fields[i]);
                                if (highlightField != null) {
                                    // 获取高亮字段的内容数据
                                    String value_hight = highlightField.getFragments()[0].toString();
                                    // 反射获取的字段
                                    Field field = clazz.getDeclaredField(fields[i]);
                                    // 暴力反射
                                    field.setAccessible(true);
                                    // 设置地段对象的value值
                                    field.set(entity, value_hight);
                                }
                            }

                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        list.add(entity);
                    }

                    return new AggregatedPageImpl<>(list, pageable, totalHits);
                }

                @Override
                public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                    return null;
                }
            });

        } else {
            // 没有查询条件的的时候，获取es中的全部数据 分页获取
            searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).build();
            page = elasticsearchTemplate.queryForPage(searchQuery, clazz);
        }

        // Mybatis中的分页对象
        Page page_list = new Page<>(pageNum, pageSize);
        // 加入集合
        page_list.addAll(page.getContent());
        // 设置总记录数
        page_list.setTotal(page.getTotalElements());
        // 转换成mybatis中的pageInfo对象
        PageInfo pageInfo = new PageInfo<>(page_list);

        // 返回值
        return pageInfo;
    }

}
